package AsLayers
{

	
	import AsLayers.BaseType.Bounds;
	import AsLayers.BaseType.LonLat;
	import AsLayers.BaseType.Pixel;
	import AsLayers.BaseType.Size;
	import AsLayers.Control.IControl;
	import AsLayers.Control.Navigation;
	import AsLayers.Layer.ILayer;
	import AsLayers.Util.Geo;
	
	import flash.events.Event;
	
	import mx.containers.Canvas;
	import mx.events.FlexEvent;

	public class Map extends Canvas
	{
		
        public var config:Object={
        	numZoomLevels:10,
        	projection:"EPSG:4326",
		    units:"degrees",
            maxExtent:new Bounds(-45,-45, 0, 45)
        }
        private var projection:String="EPSG:4326"
        private var units:String="degrees"
        private var numZoomLevels:int=10
        private var zoom:int=0
        private var scales:Array
        private var resolutions:Array
        private var minScale:Number=AUTO
        private var maxScale:Number=AUTO
        private var maxResolution:Number=AUTO
        private var minResolution:Number=AUTO
        private var minExtent:Bounds
        private var maxExtent:Bounds
        private var layers:Array=new Array()
        private var controls:Array=new Array()
        private var center:LonLat
        private var _mapStaus:int=0
        private var markerLayer:AsLayers.Layer.Marker
        protected var _layerContainer:Canvas=new Canvas()
        protected var _controlContainer:Canvas=new Canvas()
        static public var AUTO:Number=-1
		public function Map(){
			super();
			this.addEventListener(FlexEvent.INITIALIZE,this._init);
			//this.re
	    }
	    public function getMapStatus():int{
	    	return _mapStaus;
	    }
        public function getLayerContainer():Canvas{
        	return this._layerContainer;
        }
        public function getControlerContainer():Canvas{
        	return this._controlContainer;
        }
        public function getNumZoomLevels():int{
        	return this.numZoomLevels
        }
        private function _init(e:Event):void{
        	
        	trace(".....init display....")
        	this.initDisplay();
        	this.addControl(new Navigation())
        	this.markerLayer=new AsLayers.Layer.Marker()
        	this.addLayer(this.markerLayer);
        	//this.markerLayer.setMap(this);
        	//this.addLayer(this.markerLayer);
        	//this.focusEnabled=false
        	this.enabled=false;
        	//this.
        }
        public function getMarkerLayer():AsLayers.Layer.Marker{
        	return this.markerLayer;
        }
        private function initDisplay():void{
        	this.horizontalScrollPolicy='off';
			this.verticalScrollPolicy='off';
            
            this._layerContainer.horizontalScrollPolicy='off';
            this._layerContainer.verticalScrollPolicy='off';
            this._layerContainer.clipContent=false
			//this._layerContainer.width;
           // this._layerContainer.height=this.height;
          // trace("p:"+this.x)
        //    this._layerContainer.x=this.x;
       //     this._layerContainer.y=this.y;
          //  this._layerContainer.setStyle("backgroundColor","#4D2626");

            this.addChild(this._layerContainer);
          //  trace("c:"+this._layerContainer.x)
            /*this._controlContainer.width=this.width;
            this._controlContainer.height=this.height;
            this._controlContainer.x=this.x;
            this._controlContainer.y=this.y;*/
            //this.addEventListener(
            this._controlContainer.horizontalScrollPolicy='off';
            this._controlContainer.verticalScrollPolicy='off';
           // this._controlContainer.alpha=0.0;
            this.addChild(this._controlContainer);
        }
        public function initMap(config:Object):void{
        	for(var key:Object in config){
				this[key]=config[key];
			}
			//this.initDisplay();
			this.initResolutions();
			this._mapStaus=1;
			this.enabled=true;
        }
        public function addControl(control:IControl):void{
        	this.controls.push(control);
        	control.setMap(this);
        	
        }
        public function pan(dx:Number,dy:Number):void{
        	var centerPixel:Pixel=this.getViewPortPxFromLonLat(this.getCenter());
        	//trace(this.getCenter())
        	//trace(centerPixel)
        	var newPixel:Pixel=centerPixel.add(dx,dy);
        	//trace(newPixel)
        	if (!newPixel.equals(centerPixel)) {
              var newCenterLonLat:LonLat = this.getLonLatFromViewPortPx(newPixel);
              //trace(newCenterLonLat)
              this.setCenter(newCenterLonLat,this.zoom);
            }
        	
        }
        public function zoomTo(zoom:int):void{
        	this.setCenter(this.getCenter(),zoom);
        }
        public function zoomOut():void{
        	this.zoomTo(this.zoom-1);
        }
        public function zoomIn():void{
        	this.zoomTo(this.zoom+1);
        }
        public  function  getLonLatFromViewPortPx (viewPortPx:Pixel):LonLat {
           var lonlat:LonLat = null;
           if (viewPortPx != null) {
             var size:Size = this.getSize();
             var center:LonLat = this.getCenter();
             if (center) {
                var res:Number  = this.getResolution();
        
                var delta_x:Number = viewPortPx.x - (size.w / 2);
                var delta_y:Number = viewPortPx.y - (size.h / 2);
            
                lonlat = new LonLat(center.lon + delta_x * res ,
                                             center.lat - delta_y * res); 
            } 
          }
          return lonlat;
        }
        public   function  getResolution():Number{
            return this.resolutions[this.zoom];
        }
        
        public function getSize():Size{
        	return new Size(this.width,this.height);
        }
        public function getExtent():Bounds{
        	return this.calculateBounds(null,-1);
        	
        }
        public function setCenter(center:LonLat,zoom:int):void{
        	
        	
        	
        	var zoomChanged:Boolean=false;
        	if(validateZoom(zoom)){
        		zoomChanged=(zoom!=this.zoom);
        		this.zoom=zoom;
        	}
        	if(!zoomChanged&&this.center!=null){
        		this.centerLayerContainer(center);    
        	}
        	this.center=center;
        	var bounds:Bounds=this.getExtent();
        	 trace("moveto:"+bounds)
        	for(var i:int=0;i<this.layers.length;i++){
        		trace("begin move")
        		var layer:ILayer=this.layers[i];
        		layer.moveTo(bounds,zoomChanged)
        	}
        }
        public function centerLayerContainer(lonlat:LonLat):void{
            var originPx:Pixel = this.getViewPortPxFromLonLat(this.getCenter());
            var newPx:Pixel = this.getViewPortPxFromLonLat(lonlat);
            if ((originPx != null) && (newPx != null)) {
                this._layerContainer.x += originPx.x - newPx.x;
                this._layerContainer.y += originPx.y - newPx.y;
                trace("new lcps:"+this._layerContainer.x +";"+this._layerContainer.y)
             }
        }
        public function getViewPortPxFromLonLat(lonlat:LonLat):Pixel{
        	 var px:Pixel = null; 
             if (lonlat != null) {
               var resolution:Number = this.getResolution();
               var extent:Bounds = this.getExtent();
               px = new Pixel(
                  Math.round(1/resolution * (lonlat.lon - extent.left)),
                  Math.round(1/resolution * (extent.top - lonlat.lat))
               );    
             }
             return px;
        }
        public function getLayerPxFromLonLat(lonlat:LonLat):Pixel{
        	   var px:Pixel = this.getViewPortPxFromLonLat(lonlat);
               return this.getLayerPxFromViewPortPx(px);   
        }
        public function getLayerPxFromViewPortPx(viewPortPx:Pixel):Pixel {
               var layerPx:Pixel = null;
               if (viewPortPx != null) {
                  var dX:Number = -this._layerContainer.x;
                  var dY:Number = -this._layerContainer.y;
                  layerPx = viewPortPx.add(dX, dY);
              }
              return layerPx;
        }
        public function getViewPortPxFromLayerPx(px:Pixel):Pixel{
        	 var viewPortPx:Pixel = null;
             if (px != null) {
                var dX:Number = this._layerContainer.x;
                var dY:Number = this._layerContainer.y;
                viewPortPx = px.add(dX, dY);            
             }
             return viewPortPx;
        }
        public function validateZoom(zoom:int):Boolean{
        	return (zoom<this.numZoomLevels && zoom>=0)
        }
        public function getMaxExtent():Bounds{
        	return this.maxExtent;
        }
        public function getCenter():LonLat{
        	if(this.center==null){
        		this.setCenter(this.maxExtent.getCenterLonLat(),this.zoom);
        	}
        	return this.center;
        }
        public  function calculateBounds(center:LonLat, resolution:Number):Bounds {
           var extent:Bounds;
           if (center == null) {
              center = this.getCenter();
            }          
              
           if (resolution == -1) {
              resolution = this.getResolution();
            }
           if ((center != null) && (resolution != -1)) {
                var size:Size = this.getSize();
                var w_deg:Number = size.w * resolution;
                var h_deg:Number = size.h * resolution;
                extent = new Bounds(center.lon - w_deg / 2,
                                           center.lat - h_deg / 2,
                                           center.lon + w_deg / 2,
                                           center.lat + h_deg / 2);
        
           }
           trace("now extent:"+extent)
           return extent;
        }

        public function addLayer(layer:ILayer):void{
        	layer.setMap(this)
        	this.layers.push(layer);
        }
	    public function  initResolutions():void {
	    	var i:int;
          if ((this.scales != null) || (this.resolutions != null)) {
             if (this.scales != null) {
                this.resolutions = [];
                for(i = 0; i < this.scales.length; i++) {
                    var scale:Number = this.scales[i];
                    this.resolutions[i] = AsLayers.Util.Geo.getResolutionFromScale(scale, 
                                                              this.units);
                }
              }
              this.numZoomLevels = this.resolutions.length;

          } else {
            
            this.resolutions = [];
             trace(this.maxResolution)
            var viewSize:Size,wRes:Number,hRes:Number;
            if (this.minScale!=AUTO) {
                this.maxResolution = 
                    AsLayers.Util.Geo.getResolutionFromScale(this.minScale, 
                                                           this.units);
            } else if (this.maxResolution==AUTO) {
                 viewSize = this.getSize();
                
                 wRes = this.maxExtent.getWidth() / viewSize.w;
                 hRes = this.maxExtent.getHeight()/ viewSize.h;
                this.maxResolution = Math.max(wRes, hRes);
                trace(viewSize)
            } 

            // determine minResolution
            if (this.maxScale !=AUTO) {           
                this.minResolution = 
                    AsLayers.Util.Geo.getResolutionFromScale(this.maxScale,null);
            } else if ( (this.minResolution==AUTO) && 
                        (this.minExtent != null) ) {
                 viewSize = this.getSize();
                 wRes = this.minExtent.getWidth() / viewSize.w;
                 hRes = this.minExtent.getHeight()/ viewSize.h;
                this.minResolution = Math.max(wRes, hRes);
            } 


            if (this.minResolution !=AUTO) {
                var ratio:Number = this.maxResolution / this.minResolution;
                this.numZoomLevels = 
                    Math.floor(Math.log(ratio) / Math.log(2)) + 1;
            }
            
            for ( i=0; i < this.numZoomLevels; i++) {
                var res:Number = this.maxResolution / Math.pow(2, i)
                this.resolutions.push(res);
            }    
        }
        
        //sort resolutions array ascendingly
        //
          this.resolutions.sort( function(a:Number, b:Number):Number {if((b-a)>=0) return 1 else return -1; } );
          this.resolutions = this.resolutions;
          this.maxResolution = this.resolutions[0];
          var lastIndex:int = this.resolutions.length - 1;
          this.minResolution = this.resolutions[lastIndex];
        
           this.scales = [];
           for( i = 0; i < this.resolutions.length; i++) {
            this.scales[i] = 
               AsLayers.Util.Geo.getScaleFromResolution(this.resolutions[i], 
                                                      this.units);
           }
           this.minScale = this.scales[0];
           this.maxScale = this.scales[this.scales.length - 1];
        
           this.numZoomLevels = this.numZoomLevels;
           //trace(this.resolutions)
      }
		
	}
}